<?php
/**
 * class for forward padameters
 *
 */ 
class ForwardParameters
{
    protected $module;
    protected $action;
    protected $parameters = array();
    public function getModule()
    {

        return $this->module;
    }
    public function getAction()
    {

        return $this->action;
    }
    public function getParameters()
    {

        return $this->parameters;
    }
    public function setAction($v)
    {
    	$this->action = $v;
    }
    public function setModule($v)
    {
        $this->module = $v;
    }
    public function setParameters($v)
    {
        $this->parameters = $v;
    }
}
//to add mark for come categories, wich products can be added to cart
class TreeObjectSettings
    {
        // Whether category is for eshop
        public $IsEshop = 0;
        // How many products belongs to category (direct)
        public $ProductsQnt = 0;
};
/**
 * Subclass for representing a row from the 'tree' table.
 *
 * 
 *
 * @package lib.model
 */ 
class Tree extends BaseTree
{
    public static function createCategory( $name, $rarentId )
    {
        $parent = $rarentId;
        $parentTree = TreePeer::retrieveByPK($parent);
        if($parentTree)
        {
            $tree = new Tree();
            $tree->setStatusId(MyConstants::STATUS_NEW);
            $tree->setObjType(MyConstants::MODULE_VIRTUAL);
            
            $parentTree->setChildrenQnt($parentTree->getChildrenQnt() + 1);
            $parentTree->save();
            //set branch
            $tree->setBranch($parentTree->getBranch() . $parentTree->getId() . ':');
            $tree->setParentId($parentTree->getId());
            $tree->save();
            $treeLng = new TreeLng();
            $treeLng->setCulture(sfContext::getInstance()->getUser()->getCulture());
            $treeLng->setName($name);
            $treeLng->setId($tree->getId());
            $treeLng->save();
            return true;
        }
        return false;
    }
    /**
     * 
     * method for info if category is for eshop
     */
    public function getObjectSettings()
    {
        $stdObj = json_decode($this->getOptionsJson());
        if($stdObj)
        {
            // Get from current tree object
            $tos = new TreeObjectSettings();
            $tos->IsEshop = $stdObj->IsEshop;
            $tos->ProductsQnt = $stdObj->ProductsQnt;
        }else 
        {
            $tos = new TreeObjectSettings();
            $tos->IsEshop = 0;
            $tos->ProductsQnt = 0;
        }
        return $tos;
    }
    public function setObjectSettings($IsEshop, $ProductsQnt = 0)
    {
        $tos = new TreeObjectSettings();
        $tos->IsEshop = $IsEshop;
        $tos->ProductsQnt = $ProductsQnt;
        $json = json_encode($tos);
        $this->setOptionsJson($json);
    }
	
	/**
     * recomended MAX length of meta information (title, description) in characters
     */
    const META_TITLE  = 66;
    const META_DESCRIPTION       = 250;
    
    protected static $m_arTreeLng = null;

    protected $m_myName = '';
    protected $m_myText = '';

    /**
     * Contains icon object (Files)
     *
     * @var Files
     */
    protected static $m_arIcons = array();
    /**
     * returns ForwardParameters object (url exploded in module, action, and array of parameters)
     */
    public function returnUrl()
    {
    	$forvardParameters = new ForwardParameters();
    	$arr = explode('/', $this->getLinkTo());
        $module = $arr[0];
        $action = !empty($arr[1]) ? $arr[1] : 'index';
        $forvardParameters->setModule($module);
        $forvardParameters->setAction($action);
        if( (!empty($arr[2])) && !empty($arr[3]) )
        {
        	$parameters = array();
            $parameters[$arr[2]] = $arr[3];
            $forvardParameters->setParameters($parameters);
        }
    	return $forvardParameters;

    }
    /**
     * sets requests parameters by given array
     * @param sfRequest $request
     * @param array $arParameters
     */
    public static function setRequestParameters( $request, $arParameters)
    {
    	foreach( $arParameters as $key => $parameter)
    	{
    	   $request->setParameter($key, $parameter);
    	}
    }
    
    /**
     * Returns true if page has assigned icon
     *
     * @return boolean
     */
    public function hasIcon()
    {
        $hasIcon = false;
        
        if( $this->id > 0 )
        {
            // Check if we have NO cached icon for this object
            if( empty( self::$m_arIcons[$this->id] ) )
            {
                // Select from DB
                $c = new Criteria();
                $c->add(FilesPeer::OBJ_TYPE, MyConstants::TYPE_TREE_PAGE);
                $c->add(FilesPeer::OBJ_ID, $this->id);
                $file = FilesPeer::doSelectOne($c);
                
                if( !$file )
                {
                    $file = new Files(); 
                }
                
                // Cache icon in array
                self::$m_arIcons[$this->id] = $file;
            }
            
            $hasIcon = strlen(self::$m_arIcons[$this->id]->getUname());
        }  // END IF ( object has ID )
        
        return $hasIcon;
    }
    
    /**
     * Returns assigned icon name, w/o full path to it
     *
     * @return string icon name
     */
    public function getIconName()
    {
        $iconname = '';
        
        if( $this->id > 0 )
        {
            // Check if we have NO cached icon for this object
            if( empty( self::$m_arIcons[$this->id] ) )
            {
                // Select from DB
                $c = new Criteria();
                $c->add(FilesPeer::OBJ_TYPE, MyConstants::TYPE_TREE_PAGE);
                $c->add(FilesPeer::OBJ_ID, $this->id);
                $file = FilesPeer::doSelectOne($c);
                
                if( !$file )
                {
                    $file = new Files(); 
                }
                
                // Cache icon in array
                self::$m_arIcons[$this->id] = $file;
            }
            
            $iconname = self::$m_arIcons[$this->id]->getUname();
        }  // END IF ( object has ID )
        
        return $iconname;
    }

    public static function create($userId, $parentId, $arOptions = array())
    {
        $created = null;

        $userId = (int)$userId;
        $parentId = (int)$parentId;
        
        if( $userId < 1 )
        {
            throw new Exception('Tree::create() bad $userId!');
        }

        if( $parentId < 1 )
        {
            throw new Exception('Tree::create() bad $parentId!');
        }


        $parent = TreePeer::retrieveByPk($parentId);
        if( empty($parent) )
        {
            throw new Exception('Tree::create() parent with ID: ' . $parentId . ' does not exists!');
        }

		if( empty( $arOptions['moduleType'] ) )
		{
			throw new Exception('Tree::create() moduleType');
		}

		if( ($arOptions['moduleType'] != MyConstants::MODULE_VIRTUAL) && ((int)$arOptions['moduleId'] < 1) )
		{
			throw new Exception('Tree::create() moduleId');
		}

        $created = new Tree();
        $created->setParentId($parent->getId());
        $created->setBranch($parent->getBranch() . $parent->getId() . ':');
		$created->setObjType($arOptions['moduleType']);
		$created->setObjId($arOptions['moduleId']);
		$created->save();
        //debugvar($created);

        return $created;
    }

    public function getName()
    {
        //debugvar(self::$m_arTreeLng);
        if( self::$m_arTreeLng == null )
            return $this->m_myName;

        if( empty( self::$m_arTreeLng[$this->getId()] ) )
            return $this->m_myName;

        //debugvar();
        return self::$m_arTreeLng[$this->getId()]->getName();
    }

    public function setText($value)
    {
        $this->m_myText = $value;
    }

    public function setName($value)
    {
        $this->m_myName = $value;
    }

    public function saveLng($culture)
    {
        if( !$this->getId() )
            throw new PropelException('Can\'t save LNG information until main object is not saved!');

        $c = new Criteria();
        $c->add(TreeLngPeer::ID, $this->getId());
        $c->add(TreeLngPeer::CULTURE, $culture);
        $treeLng = TreeLngPeer::doSelectOne($c);
        //debugvar($treeLng);
        if( empty($treeLng) )
        {
            $sql = sprintf(
                'INSERT INTO %s (%s, %s, %s, %s) VALUES (%d, "%s", "%s", "%s")'
                , TreeLngPeer::TABLE_NAME
                , TreeLngPeer::ID
                , TreeLngPeer::CULTURE
                , TreeLngPeer::NAME
                , TreeLngPeer::TEXT
                , $this->getId()
                , mysql_real_escape_string($culture)
                , mysql_real_escape_string($this->m_myName)
                , mysql_real_escape_string($this->m_myText)
            );
        }else
        {
            $sql = sprintf(
                'UPDATE %s SET %s = "%s", %s = "%s" WHERE %s = %d AND %s = "%s" LIMIT 1'
                , TreeLngPeer::TABLE_NAME
                , TreeLngPeer::NAME
                , mysql_real_escape_string($this->m_myName)
                , TreeLngPeer::TEXT
                , mysql_real_escape_string($this->m_myText)
                , TreeLngPeer::ID
                , intval($this->getId())
                , TreeLngPeer::CULTURE
                , mysql_real_escape_string($culture)
            );

            //$treeLng->setId($this->getId());
            //$treeLng->setCulture($culture);
            //$treeLng->setName($this->m_myName);
            //$treeLng->setText($this->m_myText);
            //debugvar($treeLng);
            //exit('saving LNG...');
            //$treeLng->save();
        }

        //debugvar($sql);
        //exit('inserting LNG...');
        $con = Propel::getConnection();
        $stmt = $con->prepareStatement($sql);
        $stmt->executeQuery();

    }

    /**
    *   Returns array of siblings by one of theirs ID
    *   @return array of Tree objects, i.e. array( 0 => Tree, 1 => Tree )
    */
    public static function getSiblings( $objId )
    {
        $arSiblings = array();

        // Get parent object
        $parent = Tree::getParentByChild($objId);
        debugvar($parent, 'Parent of: ' . $objId);

        // Select all children by parent ID if parent exists
        if( $parent != null )
        {
            $c = new Criteria();
            $c->add(TreePeer::PARENT_ID, $parent->getId());
            $arSiblings = TreePeer::doSelect($c);
        }

        return $arSiblings;
    }

    /**
    *   Returns parent by child ID
    *   @return Tree object or null if not found
    */
    public static function getParentByChild( $objId )
    {
        $parent = null;

        $obj = TreePeer::retrieveByPk($objId);
        if( !empty($obj) )
        {
            $parent = TreePeer::retrieveByPk($obj->getParentId());
        }

        return $parent;
    }

    /**
    *   Extracts Tree from $parentTreeId, returns as plain array
    */
    public static function getTreeIds( $parentTreeId )
    {
        $arIds = array();
        //debugvar('Selecting tree for parent ID: ' . $parentTreeId);
        $c = new Criteria();
        if($parentTreeId)
        {
            $parent = TreePeer::retrieveByPk($parentTreeId);
            if( $parent )
            {
                $arIds[] = $parent->getId();
            }

            $c->add(TreePeer::BRANCH, Tree::getById($parentTreeId)->getBranch() . $parentTreeId . ':%', Criteria::LIKE);
        }
        $ar = TreePeer::doSelect($c);
        foreach( $ar as $obj )
            $arIds[] = $obj->getId();
        //debugvar($arIds);

        return $arIds;
    }

    /**
    *   Returns tree array by $label or empty in case error
    */
    public static function getTreeByLabel($label, $lng = 'lt')
    {
        $arBranch = array();
        $c = new Criteria();
        $c->add(TreePeer::LABEL, strtoupper($label));
        $obj = TreePeer::doSelectOne($c);

        if( !empty($obj) )
        {
            $arBranch = Tree::getTree($obj->getId(), $lng);
        }

        return $arBranch;
    }

    /**
    *   Returns tree array from $parentTreeId, with language information
    */
    public static function getTree( $parentTreeId, $lng = 'lt' )
    {
        $arBranch = array();
        // Gather all IDs to extract LNG information
        $arPks = array();
        //debugvar('Selecting tree for parent ID: ' . $parentTreeId);
        $c = new Criteria();
        if($parentTreeId)
        {
            $parent = TreePeer::retrieveByPk($parentTreeId);
            if( $parent )
            {
                $arPks[$parentTreeId] = $parentTreeId;
                $arBranch[] = array(
                //$arBranch[$parent->getId()] = array(
                    'id' => $parent->getId()
                    , 'obj' => $parent
                    , 'parentId' => $parent->getParentId()
                    , 'children' => array()
                );
            }
            $c->addDescendingOrderByColumn(TreePeer::PRIORITY);
            $c->add(TreePeer::BRANCH, Tree::getById($parentTreeId)->getBranch() . $parentTreeId . ':%', Criteria::LIKE);
        }
        $ar = TreePeer::doSelect($c);

        // Let's scan all records and format tree array
        foreach($ar as $obj)
        {
            $id = $obj->getId();
            $arPks[$id] = $id;
            $parentId = $obj->getParentId();

            if( ($parentId == 0)/* || ($parentTreeId == $parentId) */)
            {
                $arBranch[] = array(
                    'id' => $id
                    , 'obj' => $obj
                    , 'parentId' => $parentId
                    , 'children' => array()
                );
            }else
            {
                self::insertChild($parentId, $arBranch, $obj);
            }
        }
        if( $lng != null )
        {
            self::$m_arTreeLng = self::getTreeLng($arPks, $lng);
        }
        //$arBranchReturn = self::sortTree($arBranch, array());
        return $arBranch;
    }
    public static function sortTree($tree, $trr1)
    {
        usort($tree, 'compareArr');
        $trr1 = $tree;
        foreach($tree as $key => $tr)
        {
            $trr1[$key]['children'] = self::sortTree($tr['children'], $trr1[$key]['children']);
        }
        return $trr1;
    }

    /**
    *   Inserts child into tree array
    */
    protected static function insertChild($parentId, &$arBranch, $obj)
    {
        //debugvar('Inserting ' . $obj->getId() . ' as child of: ' . $parentId);
        foreach($arBranch as $key => $ar)
        {
            //debugvar('ID: ' . $key);
            if( $ar['id'] == $parentId )
            //if( $key == $parentId )
            {
                //debugvar('Got parent object: ' . $key);
                $arBranch[$key]['children'][] = array(
                //$arBranch[$key]['children'][$obj->getId()] = array(
                    'id' => $obj->getId()
                    , 'obj' => $obj
                    , 'parentId' => $obj->getParentId()
                    , 'children' => array()
                );
                return;
            }elseif( count($ar['children']) )
            {
                //debugvar('Need to dive into children of: ' . $key . ' to get parent for ' . $obj->getId());
                self::insertChild($parentId, $arBranch[$key]['children'], $obj);
            }
        }

        //debugvar('Branch ID: ' . $obj->getId() . ' was NOT inserted!!!');

        //debugvar($arBranch, 'Branch for parent ID: ' . $parentId);
    }

    /**
    *   Returns language information for given array of primary key
    */
    public static function getTreeLng( $arPks, $lng = 'lt' )
    {
        //self::$m_arTreeLng = array();
        $c = new Criteria();
        $c->add(TreeLngPeer::CULTURE, $lng);
        if( ($totalR = count($arPks)) )
        {
            $criterion = $c->getNewCriterion(TreeLngPeer::ID, $arPks, Criteria::IN);
            //foreach( $arPks as $id )
            //{
            //    $criterion = $c->getNewCriterion(TreeLngPeer::ID, $id);
                
            //}
            $c->addAnd($criterion);
        }  // END IF
        //debugvar($c);
        $arObj = array();
        $ar = TreeLngPeer::doSelect($c);
        foreach( $ar as $obj )
            $arObj[$obj->getId()] = $obj;
        //self::$m_arTreeLng = $arObj;
        //debugvar(self::$m_arTreeLng);

        return $arObj;
    }

    /**
    *   TODO: finish prioritizing :)
    */
    static function applyPriority( &$arBranch, $level = 1 )
    {
        //self::debugChildren($arBranch);
        debugvar($arBranch[0]['children']);
        //debugvar(array_pop($arBranch[0]['children']), 'First:');
        $stack[] = $arBranch[0]['children'];
        

        $arSortedBranch[] = array(
            'id' => $arBranch[0]['id']
            , 'obj' => $arBranch[0]['obj']
            , 'parentId' => $arBranch[0]['parentId']
            , 'children' => array()
        );

        // List all values
        while( ($branch = array_pop($stack)) )
        {
            $arToSort = array();
            for( $i = 0; $i < count($branch); $i++ )
            {
                $arToSort[$branch[$i]['id']] = $branch[$i]['obj']->getPriority();
                $arChildren[$branch[$i]['id']] = $branch[$i];
            }
            //self::debugChildren($arChildren);
            //self::debugChildren($arToSort);
            debugvar($arToSort, 'To sort:');
            arsort($arToSort);
            debugvar($arToSort, 'Sorted:');
            debugvar('---------------------------------');

            $arSorted = array();
            foreach( $arToSort as $key => $value )
            {

                $arSorted[$key] = $arChildren[$key];
                $arSortedBranch[] = array(
                    'id' => $arChildren[$key]['id']
                    , 'obj' => $arChildren[$key]['obj']
                    , 'parentId' => $arChildren[$key]['parentId']
                    , 'children' => array()
                );
            }
            debugvar($arSorted);
        }

        debugvar($arSortedBranch, 'Branch sorted:');
    }

    /**
    *   Skips 2 item on position $pos1 w/ item on position $pos2 in $ar
    */
    protected static function skip($ar, $pos1, $pos2)
    {
        $obj = $ar[$pos1];
        $ar[$pos1] = $pos2;
        $ar[$pos2] = $obj;
    }

/*
    public function save($con = null)
    {
        if( $this->getParentId() )
        {
            $parent = TreePeer::retrieveByPk($this->getParentId());
            $parent->setChildrenQnt($parent->getChildrenQnt() + 1);
            debugvar($parent);
            $this->setBranch($parent->getBranch() . $parent->getId() . ':');
            //debugvar($this);
            //exit('saving...');
            $parent->save();
        }

        parent::save();
    }
*/

    /**
    *   Returns Tree object, either by $id either newly created
    */
    public static function getById($id)
    {
        $obj = TreePeer::retrieveByPk($id);
        if( empty($obj) )
            $obj = new Tree();

        return $obj;
    }

    /**
    *   Returns Tree object by label or null
    */
    public static function getByLabel($l)
    {
		$c = new Criteria();
		$c->add(TreePeer::LABEL, $l);
        $obj = TreePeer::doSelectOne($c);

        return $obj;
    }

    /**
    *   Returns array of Tree objects, taken by branch
    *   @param string $branch branch to be extracted, i.e. "1:2:40:43"
    *   @param string $lng language for language information
    *   @return array of Tree objects, by ID (array( '1' => Tree, '2' => Tree ))
    */
    public static function getBranchObjects($branch, $lng)
    {
        $arBranch = array();
        
        // set $arIds variable. else error when first cycle not conducted
        $arIds = null;
        if( $branch )
        {
            // Convert branch to array of PKs
            $ar = explode(':', $branch);
            $totalR = count($ar);
            
            for($i = 0; $i < $totalR; $i++)
            {
                if( $ar[$i] )
                {
                    // Create empty to ensure it will be in path
                    $arBranch[$ar[$i]] = null;
                    $arIds[$ar[$i]] = $ar[$i];
                }
            }
            //debugvar($arIds, 'IDs of Tree object to extract');

            // Get Tree and TreeLng from DB
            $ar = TreePeer::retrieveByPks($arIds);
            $arLng = Tree::getTreeLng($arIds, $lng);
            //debugvar($arLng);

            // Assign language information to array of Tree
            foreach( $ar as $tree )
            {
                $arBranch[$tree->getId()] = $tree;
                if( !empty( $arLng[$tree->getId()] ) )
                    $arBranch[$tree->getId()]->setName($arLng[$tree->getId()]->getName());
            }
        }

        //debugvar($arBranch, 'Translated path to object:');

        return $arBranch;
    }

    /**
    *   Returns array of Tree objects, taken by object ID
    *   @param integer $objId object ID branch to be extracted
    *   @param string $lng language for language information
    *   @return array of Tree objects, by ID (array( '1' => Tree, '2' => Tree ))
    */
    public static function getBranchById($objId, $lng)
    {
        $arBranch = array();

        if( $objId )
        {
            $obj = TreePeer::retrieveByPk($objId);
            $arBranch = Tree::getBranchObjects($obj->getBranch(), $lng);
        }

        return $arBranch;
    }

    static function debugChildren($ar)
    {
        $str = "\n";
        for($i = 0; $i < count($ar); $i++)
        {
            $str .= $i . ': ' . $ar[$i]['obj']->getId() . ' priority: ' . $ar[$i]['obj']->getPriority() . "\n";
            debugvar($i . ': ' . $ar[$i]['obj']->getId() . ' priority: ' . $ar[$i]['obj']->getPriority());
        }

        log_this($str);
    }

	static function isMain() 
	{
	    $action = sfContext::getInstance()->getRequest()->getParameter('action');
		if( $action == 'welcome') 
		{
		    return 'active';
		}
		else 
		{
		    return '';
		}
	}

	static function getCurrent($tree) 
	{
	    if( $tree['obj']->getChildrenQnt() == 0 ) 
        {
            return 'leaf';
        }
        else
        {
            if( sfContext::getInstance()->getRequest()->getParameter('module') == 'textmodule' && sfContext::getInstance()->getRequest()->getParameter('action') == 'page' && sfContext::getInstance()->getRequest()->getParameter('id') == $tree['obj']->getObjId() ) 
            {
                return 'collapsed'; //turi buti expanded
            }
            else
            {
                return 'collapsed';
            }
        }
        
	}

	static function isCurrent($param, $tree) 
	{
		$c = new Criteria();
		$c->add(TreePeer::OBJ_ID, $param);
	    $newTree = TreePeer::doSelectOne($c);
		if( $newTree->getId() == $tree->getParentId()) 
		{
		    return true;
		}
		else 
		{
		    return false;
		}
	}
	
/**
     * delete objs by module type and objId
     * !! only textmodule, category, FAQ and gallery so far!!
     */
    public static function deleteObjByType($objType, $objId)
    {
       switch($objType)
        {
            case MyConstants::TYPE_GALLERY:
                $gallery = GalleryPeer::retrieveByPK($objId);
                if ($gallery)
                {
                    $gallery->delete();
                }
                break;
            case MyConstants::TYPE_TEXTMODULE:
                $textmodule = TextModulePeer::retrieveByPK($objId);
                if ($textmodule)
                {
                    $textmodule->delete();
                }
                break;
            case MyConstants::TYPE_CATEGORY:
                $category = CategoryPeer::retrieveByPK($objId);
                if ($category)
                {
                    $category->delete();
                }
            case MyConstants::TYPE_FAQ:
                $faq = FaqPeer::retrieveByPK($objId);
                if ($faq)
                {
                    $faq->delete();
                }
                break;
        }
    }
    
    /**
     * delete children modules objects by deleting tree object
     */
    public function delete($con = null)
    {
        self::deleteObjByType($this->obj_type, $this->obj_id);
        //remove lg info from db
        $c = new Criteria();
        $c->add(TreeLngPeer::ID, $this->getId());
        $treeLngs = TreeLngPeer::doSelect($c);
        if($treeLngs)
        {
            foreach( $treeLngs as $obj )
            {
                $obj->delete();
            }
        }
        //reduce children qnt
        $parent = TreePeer::retrieveByPK($this->getParentId());
        
        if($parent)
        {
            $parent->setChildrenQnt($parent->getChildrenQnt()-1);
            $parent->save();
        }
        if( $this->getChildrenQnt() )
        {
            $arPks = Tree::getTreeIds($this->getId());
            $c = new Criteria();
            $c->add(TreePeer::ID, $arPks, Criteria::IN);
            TreePeer::doDelete($c);
            //delete values from lng table too
            $clng = new Criteria();
            $clng->add(TreeLngPeer::ID, $arPks, Criteria::IN);
            TreeLngPeer::doDelete($clng);
        }
        parent::delete($con);
    }

}
